package fem2.gui.pm;

import fem2.Force;
import fem2.Load;
import fem2.Model;
import fem2.gui.src.HofemSource;
import fem2.gui.src.HofemSymbolsSource;
import inf.vtk.pm.SymbolsDP;

import java.beans.PropertyChangeEvent;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import vtk.vtkPolyData;

public class HofemSymbolsDP extends HofemDataProvider implements SymbolsDP {

	private static final String DISTRIBUTED_LOAD = "distributed loads";
	private static final String POINT_LOAD = "point load";
	private static final String POINT_MOMENT = "point moment";
	private static final String ROTATIONAL_CONSTRAINT = "rotational constraint";
	private static final String TRANSLATIONAL_CONSTRAINT = "translational constraint";

	private double[] distributedLoadValueRange_;

	private Map<String, HofemSymbolsSource> sources_ = new HashMap<String, HofemSymbolsSource>();

	public HofemSymbolsDP() {
		super();

		sources_.put(DISTRIBUTED_LOAD, new HofemSymbolsSource.BCSLoadSource());
		sources_.put(POINT_LOAD, new HofemSymbolsSource.BCSForceSource());
		sources_.put(POINT_MOMENT, new HofemSymbolsSource.BCSMomentSource());
		sources_.put(ROTATIONAL_CONSTRAINT, new HofemSymbolsSource.BCSRotSource());
		sources_.put(TRANSLATIONAL_CONSTRAINT, new HofemSymbolsSource.BCSTransSource());
	}

	public vtkPolyData getDistributedLoadData() {
		return getPD(DISTRIBUTED_LOAD);
	}

	public double[] getDistributedLoadValueRange() {
		if (distributedLoadValueRange_ == null) {
			Model m = getCastedModel().getModel();
			int nl = m.countLoads();

			distributedLoadValueRange_ = new double[] { 0, 1 };

			for (int i = 0; i < nl; i++) {
				minMaxLoad(m.getLoad(i), distributedLoadValueRange_);
			}
		}
		return distributedLoadValueRange_;
	}

	private vtkPolyData getPD(String name) {
		return sources_.get(name).GetPolyDataOutput();
	}

	public vtkPolyData getPointLoadData() {
		return getPD(POINT_LOAD);
	}

	public double[] getPointLoadValueRange() {
		return new double[] { -1, 1 };
	}

	public vtkPolyData getPointMomentData() {
		return getPD(POINT_MOMENT);
	}

	public vtkPolyData getRotationalConstraintData() {
		return getPD(ROTATIONAL_CONSTRAINT);
	}

	@Override
	protected List<HofemSource> getSources() {
		return new LinkedList<HofemSource>(sources_.values());
	}

	public vtkPolyData getTranslationalConstraintData() {
		return getPD(TRANSLATIONAL_CONSTRAINT);
	}

	private void minMaxLoad(double[] values, double[] loadRange) {
		for (double v : values) {
			if (v < loadRange[0]) {
				loadRange[0] = v;
			}
			if (v > loadRange[1]) {
				loadRange[1] = v;
			}
		}
	}

	private void minMaxLoad(Load l, double[] loadRange) {
		if (l instanceof Force) {
			minMaxLoad(((Force) l).getValues(), loadRange);
		} else {
			/*
			 * TODO
			 */
			throw new Error("not implemented");
		}
	}

	// private void minMaxLoad(EdgeLoad load, double[]
	// distributedLoadValueRange) {
	// // int d = getCastedModel().countFields();
	// int d = 1;
	//
	// for (int i = 0; i < d; i++) {
	// minMaxLoad(load.getValue(0), distributedLoadValueRange);
	// }
	// }
	//
	// private void minMaxLoad(FunctionR2ToR load, double[] loadRange) {
	// if (load != null) {
	// double[] values = { load.valueAt(-1, -1), load.valueAt(1, -1),
	// load.valueAt(1, 1), load.valueAt(-1, 1), load.valueAt(0, 0) };
	// minMaxLoad(values, loadRange);
	// }
	// }
	//
	// private void minMaxLoad(FaceLoad load, double[]
	// distributedLoadValueRange) {
	// int d = getCastedModel().getModel().countFields();
	//
	// for (int i = 0; i < d; i++) {
	// minMaxLoad(load.getValue(i), distributedLoadValueRange);
	// }
	// }
	//
	// private void minMaxLoad(FunctionRToR load, double[] loadRange) {
	// if (load != null) {
	// double[] values = { load.valueAt(-1), load.valueAt(0),
	// load.valueAt(1) };
	// minMaxLoad(values, loadRange);
	// }
	// }
	//
	// private void minMaxLoad(Load l, double[] distributedLoadValueRange) {
	// if (l instanceof EdgeLoad) {
	// EdgeLoad el = (EdgeLoad) l;
	// minMaxLoad(el, distributedLoadValueRange_);
	// } else if (l instanceof FaceLoad) {
	// FaceLoad fl = (FaceLoad) l;
	// minMaxLoad(fl, distributedLoadValueRange);
	// }
	// }

	@Override
	protected void modelChange(PropertyChangeEvent evt) {
		distributedLoadValueRange_ = null;
	}

	public boolean providesData() {
		return getModel() != null;
	}

	public void setDisplacementScale(double scale) {
	}

	@Override
	protected void solutionChanged(PropertyChangeEvent p) {
	}
}
